/**
 * 
 */
package edu.umd.clip.lm.questions;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import edu.umd.clip.lm.factors.FactorTuple;
import edu.umd.clip.lm.model.data.Context;
import edu.umd.clip.lm.util.*;
import edu.umd.clip.lm.model.*;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class BinaryPrefixQuestion extends Question {
	// index only makes sense when aboutHidden == false;
	
	private BinaryPrefix prefix;
	
	public BinaryPrefixQuestion(byte time, byte index, boolean aboutHidden, BinaryPrefix prefix) {
		super(time, aboutHidden);
		this.prefix = prefix;
		this.index = index;
	}
	
	public BinaryPrefixQuestion(byte time, boolean aboutHidden, BinaryPrefix prefix) {
		super(time, aboutHidden);
		this.prefix = prefix;
	}
	
	public BinaryPrefixQuestion(Element xmlnode) {
		super(xmlnode);
		Element node = (Element) xmlnode.getElementsByTagName(BinaryPrefix.XML_ELEMENT_NAME).item(0);
		this.prefix = new BinaryPrefix(node);
	}
	
	public static Question fromXML(Element xmlnode) {
		return new BinaryPrefixQuestion(xmlnode);
	}
	
	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#createXML(org.w3c.dom.Document)
	 */
	@Override
	public Element createXML(Document doc) {
		Element element = super.createXML(doc);
		element.appendChild(prefix.createXML(doc));
		return element;
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#getQuestionType()
	 */
	@Override
	public int getQuestionType() {
		return BINARY_PREFIX_QUESTION;
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#test(edu.umd.clip.lm.model.training.Context)
	 */
	@Override
	public boolean test(Context ctx) {
		FactorTuple tuple = new FactorTuple(ctx.data[ctx.data.length + getTimeOffset()]);
		if (isAboutHidden()) {
			return prefix.isPrefixOf(Experiment.getInstance().getHiddenPrefix(tuple));
		} 
		return prefix.isPrefixOf(Experiment.getInstance().getWordPrefix(tuple.getValue(index)));
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#implication(edu.umd.clip.lm.questions.Question, boolean)
	 */
	@Override
	public Boolean implication(Question q, boolean value) {
		if (q.getQuestionType() != BINARY_PREFIX_QUESTION || 
				q.timeOffset != timeOffset ||
				q.aboutHidden != aboutHidden)
		{
			return null;
		}
		BinaryPrefixQuestion bpq  = (BinaryPrefixQuestion) q;
		if (aboutHidden && bpq.index != index) {
			return null;
		}
		if (prefix.equals(bpq.prefix)) {
			return value ? Boolean.TRUE : Boolean.FALSE;
		}
		if (prefix.isPrefixOf(bpq.prefix)) {
			return value ? Boolean.TRUE : null;
		} else if (bpq.prefix.isPrefixOf(prefix)) {
			return value ? null : Boolean.FALSE;
		}
		return value ? Boolean.FALSE : null;
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#testCut(java.util.Collection)
	 */
	@Override
	public TestResult test(AbstractProbTree[] context) {
		AbstractProbTree item = context[-(1+getTimeOffset())];
		if (isAboutHidden()) {
			Boolean res = item.testCut(prefix);
			if (res == null) {
				return new TestResult(item, prefix);
			}
			return new TestResult(res.booleanValue());
		}
		return new TestResult(prefix.isPrefixOf(item.getWordPrefix()));
	}
	
	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#testCut(java.util.Collection)
	 */
	@Override
	public TestResult test(AbstractProbTree item) {
		if (isAboutHidden()) {
			Boolean res = item.testCut(prefix);
			if (res == null) {
				return new TestResult(item, prefix);
			}
			return new TestResult(res.booleanValue());
		}
		return new TestResult(prefix.isPrefixOf(item.getWordPrefix()));
	}
	
	/**
	 * @return the prefix
	 */
	public BinaryPrefix getPrefix() {
		return prefix;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		String s = "[BinaryPrefixQuestion: time="+Integer.toString(timeOffset) +
			(isAboutHidden() ? " hidden" : " word") +
			" prefix=" + prefix.toString() +"]";
		return s;
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.questions.Question#toShortString()
	 */
	@Override
	public String toShortString() {
		return super.toShortString() + ' ' + prefix.toString();
	}

}
